package guijavacommander;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.io.FileSystemUtils;
import org.apache.commons.io.FileUtils;
import org.jvnet.flamingo.bcb.BreadcrumbBarModel;
import org.jvnet.flamingo.bcb.BreadcrumbItem;
import org.jvnet.flamingo.bcb.BreadcrumbPathEvent;
import org.jvnet.flamingo.bcb.BreadcrumbPathListener;
import org.jvnet.flamingo.bcb.core.BreadcrumbFileSelector;

import javax.swing.*;
import javax.swing.tree.TreeNode;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.*;
import java.net.URLDecoder;
import java.util.ArrayList;

/**
 * User: Deady
 * Date: 15.07.2009
 * Time: 19:05:36
 */
public class FilePanel extends JPanel {

    private Log logger = LogFactory.getLog(FilePanel.class);
    private JLabel currentFileLabel = new JLabel();
    private JLabel freeSpaceLabel = new JLabel();
    private BreadcrumbFileSelector currentFileBar;
    private TreeList fileList = new TreeList();
    private JLabel statusLabel = new JLabel("dir");
    private JPanel currentFilePanel = new JPanel(new BorderLayout());
    private JPopupMenu popup;
    private TabCaptionListener tabCaptionListener = null;
    private boolean adjustBreadcump = false;
    private boolean breadcumpEvent = false;
    private JButton favouritesButton;


    public FilePanel(File start) throws IOException {


        TreeListModel model = new TreeListModel(new FileSystemModel());
        fileList.setModel(model);
        initBookmarks();

        fileList.addPropertyChangeListener("currentElement", new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent evt) {
                TreeListModel model = (TreeListModel) fileList.getModel();
                FileTreeNode node = (FileTreeNode) model.getElementAt((Integer)evt.getNewValue());
                File f = (File) node.getUserObject();
                statusLabel.setText(f.isFile() ? f.length() + " b" : "dir");

            }
        });
        model.addPropertyChangeListener("currentParent", new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent evt) {
                updateCurrentFolder();
            }
        });

        currentFileBar = new BreadcrumbFileSelector();
        currentFileBar.setFocusable(false);
        currentFileBar.getModel().addPathListener(new BreadcrumbPathListener() {
            public void breadcrumbPathEvent(BreadcrumbPathEvent breadcrumbPathEvent) {
                if (adjustBreadcump) {
                    return;
                }
                final BreadcrumbBarModel<File> breadcrumbBarModel = currentFileBar.getModel();
                BreadcrumbItem<File> item = breadcrumbBarModel.getItem(breadcrumbBarModel.getItemCount()-1);
                final File folder = item.getData();
                try {
                    breadcumpEvent = true;
                    logger.trace("Setting current folder in bcb event");
                    setCurrentFolder(folder);
                    breadcumpEvent = false;
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
        });

        favouritesButton = new JButton("*");
        favouritesButton.setMinimumSize(new Dimension(20, 20));
        favouritesButton.setMaximumSize(new Dimension(20, 20));
        favouritesButton.setPreferredSize(new Dimension(20, 20));
        favouritesButton.setMargin(new Insets(0, 0, 0, 0));
        favouritesButton.setRolloverEnabled(true);
        favouritesButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                logger.trace("Showing favourites popup");
                popup.show(currentFilePanel, favouritesButton.getX(), favouritesButton.getY()+favouritesButton.getHeight());
            }
        });



        setCurrentFolder(start);
        fileList.setCurrentElement(0);
        initGui();
    }

    public void updateCurrentFolder() {
        logger.trace("Updating current folder view");
        final File folder = getCurrentFolder();
        adjustBreadcump = true;
        if (!breadcumpEvent) {
            currentFileBar.setPath(folder);
        }
        if (tabCaptionListener!=null) {
            tabCaptionListener.setTabCaption(folder.getName());
        }
        currentFileLabel.setText(folder.getAbsolutePath()+"/"+"*");//todo replace on showing mask
        long free = 0;// folder.getFreeSpace();
        try {
            free = FileSystemUtils.freeSpaceKb(folder.getAbsolutePath());
        } catch (IOException e) {
            logger.error("Using File.getFreeSpace()", e);
            free = folder.getFreeSpace();
        }
        long total = folder.getTotalSpace();
        freeSpaceLabel.setText(FileUtils.byteCountToDisplaySize(free*1024)+" of "
                +FileUtils.byteCountToDisplaySize(total) + " free");

    }

    public File getCurrentFolder() {
        TreeListModel model = (TreeListModel) fileList.getModel();
        final FileTreeNode currentParent = (FileTreeNode) model.getCurrentParent();
        return (File) currentParent.getUserObject();
    }

    public File getCurrentFile() {
        TreeListModel model = (TreeListModel) fileList.getModel();
        FileTreeNode node = (FileTreeNode) model.getElementAt(fileList.getCurrentElement());
        return (File) node.getUserObject();
    }



    private void initBookmarks() throws IOException {
        logger.trace("Initializing bookmarks popup.");
        popup = new JPopupMenu();
        for (final File bookmark : findBookmarks()) {
            final JMenuItem menuItem = new JMenuItem(bookmark.getName());
            popup.add(menuItem);
            menuItem.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    try {
                        setCurrentFolder(bookmark);
                    } catch (FileNotFoundException e1) {
                        e1.printStackTrace();
                    }
                }
            });
        }
    }

    private void initGui() {
        logger.trace("Initializing gui.");
        currentFileLabel.setForeground(Color.WHITE);
        //currentFilePanel.setBackground(Color.BLUE);
        currentFilePanel.add(currentFileBar);
        currentFilePanel.add(favouritesButton, BorderLayout.EAST);
        currentFilePanel.add(freeSpaceLabel, BorderLayout.NORTH);
        //currentFilePanel.add(currentFileLabel);

        setLayout(new BorderLayout());
        add(currentFilePanel, BorderLayout.NORTH);
        JScrollPane sp = new JScrollPane(fileList);
        sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
        add(sp, BorderLayout.CENTER);
        add(statusLabel, BorderLayout.SOUTH);
    }


    public TreeList getFileList() {
        return fileList;
    }



    public void setCurrentFolder(File file) throws FileNotFoundException {
        logger.trace("Setting current folder: "+file);
        File folder;
        if (file.isFile()) {
            folder = file.getParentFile();
        }
        else {
            folder = file;
        }
        TreeListModel model = (TreeListModel) fileList.getModel();
        FileSystemModel treeModel = (FileSystemModel) model.getTreeModel();
        TreeNode folderNode = treeModel.findNode(folder);
        model.setCurrentParent(folderNode);
        updateCurrentFolder();
        fileList.setCurrentElement(0);
    }

    public void selectFile(File file) throws FileNotFoundException {
        logger.trace("Selecting file: "+file);
        TreeListModel model = (TreeListModel) fileList.getModel();
        FileTreeNode parent = (FileTreeNode) model.getCurrentParent();
        FileTreeNode node = null;
        for (FileTreeNode c : parent.getChildren()) {
            if (c.getUserObject().equals(file)) {
                node = c;
                break;
            }
        }
        if (node==null) {
            throw new FileNotFoundException("Can't find "+file+" in "+parent.getUserObject());
        }

        int index = parent.getIndex(node);
        if (parent.equals(model.getTreeModel().getRoot())) {
            fileList.setCurrentElement(index);
        }
        else {
            fileList.setCurrentElement(index+1); //skip ".."           
        }
    }


    private File[] findBookmarks() throws IOException {
        logger.trace("Reading bookmarks");
        File bookFile = new File(System.getProperty("user.home"), ".gtk-bookmarks");
        DataInput in = new DataInputStream(new FileInputStream(bookFile));
        String s;
        java.util.List<File> res = new ArrayList<File>();
        while ((s=in.readLine())!=null) {
            if (s.startsWith("file://")) {
                s = s.replaceFirst("file://", "");
                res.add(new File(URLDecoder.decode(s, "utf-8")));
            }
        }
        return res.toArray(new File[res.size()]);
    }


    public File[] getSelectedFiles() {
        Object[] sel = fileList.getSelectedValues();
        if (sel!=null && sel.length>0) {
            File[] res = new File[sel.length];
            int i = 0;
            for (Object d : sel) {
                final FileTreeNode at = (FileTreeNode) d;
                res[i] = (File) at.getUserObject();
                i++;
            }
            return res;
        }
        else {
            final FileTreeNode at = (FileTreeNode) fileList.getModel().getElementAt(fileList.getCurrentElement());
            return new File[] {(File) at.getUserObject()};
        }
    }


    public void refresh() {
        logger.debug("Refreshing files in "+getCurrentFolder());
        TreeListModel model = (TreeListModel) fileList.getModel();
        FileTreeNode node = (FileTreeNode) model.getCurrentParent();
        node.setLoaded(false);
        model.refresh();
        if (fileList.getCurrentElement()>=model.getSize()) {//when last file is removed
            fileList.setCurrentElement(model.getSize()-1);
        }
    }

    public void selectAll() {
        fileList.setSelectionInterval(0, fileList.getModel().getSize()-1);
    }

    public void inverseSelection() {
        int[] indecied = fileList.getSelectedIndices();
        java.util.List<Integer> indA = new ArrayList<Integer>();
        for (int i : indecied) {
            indA.add(i);
        }
        final int capacity = fileList.getModel().getSize() - indA.size();
        int[] reverse = new int[capacity];
        int k = 0;
        for (int i = 0; i < fileList.getModel().getSize(); i++) {
            if (!indA.contains(i)) {
                reverse[k++] = i;
            }
        }
        fileList.setSelectedIndices(reverse);
    }

    public void deselectAll() {
        fileList.clearSelection();
    }


    public TabCaptionListener getTabCaptionListener() {
        return tabCaptionListener;
    }

    public void setTabCaptionListener(TabCaptionListener tabCaptionListener) {
        this.tabCaptionListener = tabCaptionListener;
    }
}
